package com.zhtools.utils;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;

public class CodecUtil {

    public static final String ALGORITHM_3DES = "DESede";

    public static final String CHARSET_ASCII = "US-ASCII";
    public static final String CHARSET_UTF8 = "UTF-8";
    public static final String CHARSET_GBK = "GBK";

    public static String encryptMD5(String src, String charset) {
        try {
            return new String(encryptMd5(src.getBytes(charset)));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public static String encryptMD5(String src) {
        return encryptMD5(src, CHARSET_UTF8);
    }

    public static String decodeBase64(String src, String charset) {
        try {
            if (charset == null) {
                return new String(decodeBase64(src.getBytes()));
            }
            return new String(decodeBase64(src.getBytes(charset)));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public static String decodeBase64(String src) {
        return decodeBase64(src, null);
    }

    public static String encodeBase64(String src, String charset) {
        try {
            if (charset == null) {
                return new String(encodeBase64(src.getBytes()));
            }
            return new String(encodeBase64(src.getBytes(charset)));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public static String encodeBase64(String src) {
        return encodeBase64(src, null);
    }

    public static char[] encryptMd5(byte[] src) {

        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] md = digest.digest(src);
            char[] res = Hex.encodeHex(md);
            return res;
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    public static String encrypt3Des(String src, String key, String srcCharset,
                                     String keyCharset, String resCharset) {
        try {
            byte[] keyBytes = keyCharset == null ? key.getBytes() : key
                    .getBytes(keyCharset);
            byte[] srcBytes = srcCharset == null ? src.getBytes() : src
                    .getBytes(srcCharset);
            byte[] bytes = encrypt3Des(srcBytes, keyBytes);
            return new String(bytes, resCharset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public static String encrypt3Des(String src, String key) {
        return encrypt3Des(src, key, CHARSET_UTF8, CHARSET_ASCII, CHARSET_UTF8);
    }

    public static String decrypt3DES(String src, String key, String srcCharset,
                                     String keyCharset, String resCharset) {
        try {
            byte[] keyByte = keyCharset == null ? key.getBytes() : key
                    .getBytes(keyCharset);
            byte[] srcByte = srcCharset == null ? src.getBytes() : src
                    .getBytes(srcCharset);
            byte[] res = decrypt3Des(srcByte, keyByte);
            return new String(res, resCharset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public static String decrypt3DES(String src, String key) {
        return decrypt3DES(src, key, CHARSET_UTF8, CHARSET_ASCII, CHARSET_UTF8);
    }

    public static byte[] encrypt3Des(byte[] src, byte[] key) {
        try {
            SecretKey deskey = new SecretKeySpec(key, ALGORITHM_3DES);
            Cipher c1 = Cipher.getInstance(ALGORITHM_3DES);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            byte[] res = c1.doFinal(src);
            return CodecUtil.encodeBase64(res);
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    public static byte[] decrypt3Des(byte[] src, byte[] key) {
        try {
            SecretKey deskey = new SecretKeySpec(key, ALGORITHM_3DES);
            Cipher c1 = Cipher.getInstance(ALGORITHM_3DES);
            c1.init(Cipher.DECRYPT_MODE, deskey);
            src = Base64.decodeBase64(src);
            return c1.doFinal(src);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    public static byte[] encodeBase64(byte[] src) {
        return Base64.encodeBase64(src, true);
    }

    public static char[] encodeHex(byte[] src) {
        return Hex.encodeHex(src);
    }

    public static byte[] decodeBase64(byte[] src) {
        return Base64.decodeBase64(src);
    }

    public static byte[] decodeHex(char[] src) {
        try {
            return Hex.decodeHex(src);
        } catch (DecoderException e) {
            throw new RuntimeException();
        }
    }

    public static String byte2Hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
            if (n < b.length - 1) hs = hs + ":";
        }
        return hs.toUpperCase();
    }
}
